#pragma once

#include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include <vector>

namespace ns_ring
{
    template <class T, size_t Cap = 5>
    class RingQueue
    {
    private:
        std::vector<T> _rq;
        sem_t _sp;  // 管理空白资源的信号量
        sem_t _sc;  // 管理数据资源的信号量
        int _pstep; // 空白资源下标
        int _cstep; // 数据资源下标
        pthread_mutex_t _pmtx;
        pthread_mutex_t _cmtx;

        int _cap;


    public:
        RingQueue(size_t cap = Cap)
            :_pstep(0)
            ,_cstep(0)
            ,_rq(cap)
            ,_cap(cap)
        {
            sem_init(&_sp, 0, cap);
            sem_init(&_sc, 0, 0);

            pthread_mutex_init(&_pmtx, nullptr);
            pthread_mutex_init(&_cmtx, nullptr);
        }

        ~RingQueue()
        {
            sem_destroy(&_sp);
            sem_destroy(&_sc);

            pthread_mutex_destroy(&_pmtx);
            pthread_mutex_destroy(&_cmtx);
        }

        void Push(const T& data)
        {
            sem_wait(&_sp);
            pthread_mutex_lock(&_pmtx);

            _rq[_pstep++] = data;
            _pstep %= _cap;

            pthread_mutex_unlock(&_pmtx);
            sem_post(&_sc);
        }

        void Pop(T* data)
        {
            sem_wait(&_sc);
            pthread_mutex_lock(&_cmtx);

            *data = _rq[_cstep++];
            _cstep %= _cap;

            pthread_mutex_unlock(&_cmtx);
            sem_post(&_sp);
        }

    };
}